using System;
using System.IO;
using System.Net;
using System.Text;

namespace Savage.DotNetLibrary.ProtocolLibrary
{
    /// <summary>
    /// An object that is designed to simplify web requests.
    /// </summary>
    public class HttpWrapper
    {
        /// <summary>
        /// Instantiates a new instance of the HttpWrapper class for the specified Uri.
        /// NOTE: A new object must be created for each separate request.
        /// </summary>
        /// <param name="uri">The uri target of the web request.</param>
        public HttpWrapper(Uri uri)
        {
            if (uri == null)
                throw new ArgumentNullException("uri");

            _webRequest = WebRequest.Create(uri);
        }

        private WebRequest _webRequest;
        /// <summary>
        /// Provides access to the WebRequest object so the client can set any additional properties.
        /// </summary>
        public WebRequest WebRequest
        {
            get { return _webRequest; }
        }

        /// <summary>
        /// Initiates a GET request.
        /// </summary>
        /// <returns>A string containing the HTML response.</returns>
        public string Get()
        {
            //Perform a GET Request on the page
            _webRequest.Method = "GET";

            return SendWebRequest(this._webRequest);
        }

        /// <summary>
        /// Initiates a POST request.
        /// </summary>
        /// <param name="postData">The data to post to the server. The client should ensure that any values are HTML encoded.</param>
        /// <returns>A string containing the HTML response.</returns>
        public string Post(string postData)
        {
            _webRequest.Method = "POST";
            _webRequest.ContentType = "application/x-www-form-urlencoded";

            ASCIIEncoding encoder = new ASCIIEncoding();
            byte[] byteArray = encoder.GetBytes(postData);

            _webRequest.ContentLength = byteArray.Length;
            using (Stream postStream = _webRequest.GetRequestStream())
            {
                postStream.Write(byteArray, 0, byteArray.Length);
            }

            return SendWebRequest(this._webRequest);
        }

        /// <summary>
        /// A static method that allows the client to provide a WebRequest object and retrieve a response.
        /// </summary>
        /// <param name="webRequest">The WebRequest object that contains the data required to perform a WebRequest.</param>
        /// <returns>A string containing the HTML response.</returns>
        public static string SendWebRequest(WebRequest webRequest)
        {
            if (webRequest == null)
                throw new ArgumentNullException("webRequest");

            using (HttpWebResponse response = (HttpWebResponse)webRequest.GetResponse())
            {
                using (Stream dataStream = response.GetResponseStream())
                {
                    using (StreamReader reader = new StreamReader(dataStream))
                    {
                        return reader.ReadToEnd();
                    }
                }
            }
        }

        public static void DownloadFile(Uri uri, string destinationPath)
    {
        DownloadFile(uri, null, destinationPath);
    }

    public static void DownloadFile(Uri uri, NetworkCredential credentials, string destinationPath)
    {
        HttpWrapper wrapper = new HttpWrapper(uri);
        if (credentials != null)
        {
            wrapper.WebRequest.Credentials = new NetworkCredential(credentials.UserName, credentials.Password);
        }
        using (HttpWebResponse response = (HttpWebResponse) wrapper.WebRequest.GetResponse())
        {
            using (Stream stream = response.GetResponseStream())
            {
                using (MemoryStream ms = new MemoryStream())
                {
                    int num;
                    byte[] buffer = new byte[4194304];
                    while ((num = stream.Read(buffer, 0, buffer.Length)) != 0)
                    {
                        ms.Write(buffer, 0, num);
                    }
                    buffer = null;
                    if (!Directory.Exists(Path.GetDirectoryName(destinationPath)))
                    {
                        Directory.CreateDirectory(Path.GetDirectoryName(destinationPath));
                    }
                    using (FileStream fs = new FileStream(destinationPath, FileMode.Create, FileAccess.Write))
                    {
                        fs.Write(ms.ToArray(), 0, (int)ms.Length);
                        fs.Close();
                    }
                    ms.Close();
                }
                stream.Close();
            }
            response.Close();
        }
    }

    }
}
